from datetime import datetime
from typing import TypeVar, Generic, List, Union, Dict

from emi.bar.data import Interval, BarData

from emi.bar.db import BarSource

T = TypeVar('T')

class PageResult(Generic[T]):


    def __init__(self,page_size:int,total_size:int):
        self._page_size = page_size
        self._total_size = total_size
        self._cur_page = 0
        self._total_page = int(total_size/page_size)
        if total_size % page_size > 0:
            self._total_page+=1
        self.turn_page(1)

    def cur_page(self)->int:
        """
        当前页面。从1开始。
        :return:
        """
        return self._cur_page

    def get_data(self)->List[T]:
        """
        返回当前页面数据,
        :return:
        """
        raise NotImplementedError()

    def on_page_change(self,new_index:int,old_index:int):
        pass

    def turn_page(self,index):
        """
        数据翻到指定页
        :param index: 从1开始
        :return:
        """
        if self._cur_page == index:
            return
        assert index > 0
        if index <= self.total_page_count():
            old_index = self._cur_page
            self._cur_page = index
            self.on_page_change(self._cur_page,old_index)

    def page_size(self):
        return self._page_size

    def total_page_count(self)->int:
        """
        总页数量
        :return:
        """
        return self._total_page

    def total_count(self):
        """
        总个数
        :return:
        """
        return self._total_size


def default_page_result(data_list:List[T],page_size = 50)->PageResult[T]:
    return _DefaultPageResult(data_list,page_size)


class _DefaultPageResult(PageResult[T]):

    def __init__(self, data_list: List[T],page_size:int):
        super().__init__(page_size,len(data_list))
        self._data_list = data_list
        self._page_data = None

    def on_page_change(self,new_index:int,old_index:int):
        self._page_data = None

    def get_data(self) -> List[T]:
        page_index = self.cur_page()
        if page_index > self.total_page_count():
            return []
        if self._page_data:
            return self._page_data

        page_data = []
        page_size = self.page_size()

        page_index_start = page_size * (page_index - 1)
        for i in range(0,page_size):
            index = page_index_start + i
            if index < self.total_count():
                page_data.append(self._data_list[index])

        self._page_data = page_data
        return  self._page_data



class BarSourcePageResult(PageResult[BarData]):

    """
    BarSource个股最新数据。
    """

    def __init__(self, source: BarSource,interval:Interval = Interval.DAILY):
        self._source = source
        self.symbol_list = source.get_symbol_list()
        super().__init__(50, len(self.symbol_list))
        self._page_data = None
        self._newest_day = None
        self.interval = interval
        self.with_detail = False
        self.day_list = source.get_day_list()


    def on_page_change(self,new_index:int,old_index:int):
        self._page_data = None

    def _load_bar_page(self,newest_day:datetime,symbols:List[str])->Dict[str,BarData]:
        ret = {}
        for symbol in symbols:
            bars = self._source.get_bars_recently(symbol, newest_day, 1, interval=Interval.DAILY,
                                                  with_detail=self.with_detail)
            if bars:
                bar = bars[0]
                ret[symbol] = bar
        return ret


    def get_data(self) -> List[BarData]:
        """
        返回最新的个股bar行情。如果某个个股没有行情数据，
        :return:
        """
        page_index = self.cur_page()
        if page_index > self.total_page_count():
            return []
        if self._page_data:
            return self._page_data
        if not self.day_list:
            return []

        newest_day = self.day_list[-1]
        page_size = self.page_size()

        page_index_start = page_size * (page_index - 1)
        symbols = []
        for i in range(0,page_size):
            index = page_index_start + i
            if index >= self.total_count():
                break
            symbol = self.symbol_list[index]
            symbols.append(symbol)
        assert len(symbols) > 0
        bar_map = self._load_bar_page(newest_day, symbols)
        page_list = []
        for symbol in symbols:
            bar = bar_map.get(symbol)
            if bar:
                page_list.append(bar)
            else:
                ### "构建一个空bar"
                page_list.append(BarData.null(symbol,bar_class_type=BarData,interval=self.interval))
        self._page_data  = page_list
        return  self._page_data

